package com.qc.ayouth.shop.admin.config.shiro;

import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;

/**
 * Shiro配置
 * 
 * @author Haojg
 * @date 2020/07/04
 */
@Configuration
public class ShiroConfig {

    @Bean
    public Realm adminAuthRealm() {
        return new AdminAuthRealm();
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(adminAuthRealm());
        return securityManager;
    }

    /**
     * 添加自己的过滤器，自定义url规则 Shiro自带拦截器配置规则
     * rest：比如/admins/user/**=rest[user],根据请求的方法，相当于/admins/user/**=perms[user：method]
     * ,其中method为post，get，delete等
     * port：比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal：//serverName：8081?queryString,其中schmal是协议http或https等，serverName是你访问的host,8081是url配置里port的端口，queryString是你访问的url里的？后面的参数
     * perms：比如/admins/user/**=perms[user：add：*],perms参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，比如/admins/user/**=perms["user：add：*,user：modify：*"]，当有多个参数时必须每个参数都通过才通过，想当于isPermitedAll()方法
     * roles：比如/admins/user/**=roles[admin],参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，当有多个参数时，比如/admins/user/**=roles["admin,guest"],每个参数通过才算通过，相当于hasAllRoles()方法。//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670/
     * anon：比如/admins/**=anon 没有参数，表示可以匿名使用
     * authc：比如/admins/user/**=authc表示需要认证才能使用，没有参数
     * authcBasic：比如/admins/user/**=authcBasic没有参数表示httpBasic认证
     * ssl：比如/admins/user/**=ssl没有参数，表示安全的url请求，协议为https
     * user：比如/admins/user/**=user没有参数表示必须存在用户，当登入操作时不做检查 详情见文档
     * http://shiro.apache.org/web.html#urls-
     * 
     * @param securityManager
     * @return org.apache.shiro.spring.web.ShiroFilterFactoryBean
     * @author Haojg
     * @date 2020/07/04
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        // 自定义url规则使用LinkedHashMap有序Map
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(16);
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/static/**", "anon");// 开放所有静态资源
        filterChainDefinitionMap.put("/uploads/**", "anon");// 开放所有上传资源
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/api/user/doLogin", "anon"); //网站用户登录请求排除
        filterChainDefinitionMap.put("/api/user/doWxMpAuth", "anon"); //微信公众号用户登录请求排除
        filterChainDefinitionMap.put("/api/user/doWxMaAuth", "anon"); //微信小程序用户登录请求排除
        filterChainDefinitionMap.put("/api/user/doQyWxMaAuth", "anon"); //企业微信小程序用户登录请求排除
        filterChainDefinitionMap.put("/api/platform/**", "anon");
        filterChainDefinitionMap.put("/", "anon"); // 登录请求排除
//        filterChainDefinitionMap.put("/MP_verify_iu3CkNqs5I2Rkhxg.txt", "anon"); // 登录请求排除

        // 登录
        factoryBean.setLoginUrl("/admin/auth/401");
        // 首页
        factoryBean.setSuccessUrl("/admin/auth/index");
        // 错误页面，认证不通过跳转
        factoryBean.setUnauthorizedUrl("/admin/auth/403");
        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return factoryBean;
    }

    /**
     * session过期控制
     * @return
     * @author fuce
     * @Date 2019年11月2日 下午12:49:49
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new AdminWebSessionManager();
        // 设置session过期时间3600s
        Long timeout=60L*1000*60; //毫秒级别
        defaultWebSessionManager.setGlobalSessionTimeout(timeout);
        return defaultWebSessionManager;
    }
    /**
     * 缓存配置
     * @return
     */
//    @Bean
//    public CacheManager cacheManager() {
//        MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();//使用内存缓存
//        return cacheManager;
//    }
    /**
     * 记住我的配置
     * @return
     */
//    @Bean
//    public RememberMeManager rememberMeManager() {
//        Cookie cookie = new SimpleCookie("rememberMe");
//        cookie.setHttpOnly(true);//通过js脚本将无法读取到cookie信息
//        cookie.setMaxAge(60 * 60 * 24);//cookie保存一天
//        CookieRememberMeManager manager=new CookieRememberMeManager();
//        manager.setCookie(cookie);
//        return manager;
//    }

    /**
     * 启用shiro注解
     *加入注解的使用，不加入这个注解不生效
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * 下面的代码是添加注解支持
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题，https://zhuanlan.zhihu.com/p/29161098
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

}
